package games.eightPuzzle.heuristics;

import games.eightPuzzle.states.*;


/**
 * @author avishl02
 * this class provides the ranking of the Corner Tiles Heuristic
 * 
 * the main idea is: if a corner tile should not be a hole and currently
 * do not contain the hole, for every adjacent tile that is in his final
 * position, if the adjacent is not involve in linear conflict ,add 2 to the MD 
 * heuristic because the adjacent tile will have to move from its position in 
 * addition to allow the corner tile to get to its place   
 */
/**
 * @author avishl02
 *
 */
public class CornerTilesHuristic implements Heuristic{

	private boolean _ver,_hor,_luc,_ruc,_llc,_rlc;

	private int[] _v = new int[12];
	private boolean[] _conf = new boolean[8];
	
	private SlidingPuzzleState _finalState = null;
	
	
	/**
	 * this function calculate if a corner adjacent tile is involve with
	 * linear conflict
	 * @param state
	 */
	private void calculateConflicts(SlidingPuzzleState state){
		
		
		
//		*1*****2*
//		8*******3
//		*********
//		7*******4
//		*6*****5*
		
		
		//1
		int tmp;
		
		tmp = state.get(0, 0);
		for(int i=3;i<_finalState.getNumCols();i++){
			if (tmp == _finalState.get(0, i)){
				_conf[0] = true;
				break;
			}
		}
		
		//2
		tmp = state.get(0, state.getNumCols()-1);
		for(int i=0;i<_finalState.getNumCols()-2;i++){
			if (tmp == _finalState.get(0, i)){
				_conf[1] = true;
				break;
			}
		}
		
		//3
		for(int i=2;i<_finalState.getNumRows();i++){
			if (tmp == _finalState.get(0, i)){
				_conf[2] = true;
				break;
			}
		}
		
		tmp = state.get(state.getNumRows()-1, state.getNumCols()-1);
		//4
		for(int i=0;i<_finalState.getNumRows()-2;i++){
			if (tmp == _finalState.get(i,state.getNumCols()-1)){
				_conf[3] = true;
				break;
			}
		}
		
		//5
		for(int i=0;i<_finalState.getNumCols()-2;i++){
			if (tmp == _finalState.get(state.getNumRows()-1, i)){
				_conf[4] = true;
				break;
			}
		}
		
		//6
		tmp = state.get(state.getNumRows()-1, 0);
		for(int i=2;i<_finalState.getNumCols();i++){
			if (tmp == _finalState.get(state.getNumRows()-1, i)){
				_conf[5] = true;
				break;
			}
		}
		
		
		//7
		for(int i=0;i<_finalState.getNumRows()-2;i++){
			if (tmp == _finalState.get(i,0)){
				_conf[6] = true;
				break;
			}
		}

		tmp = state.get(0, 0);
		//8
		for(int i=2;i<_finalState.getNumRows();i++){
			if (tmp == _finalState.get(i,0)){
				_conf[7] = true;
				break;
			}
		}
	}
	
	
	/**
	 * helper who saves key tiles of the final state configuration
	 * @param fs
	 */
	private void loadNumbers(SlidingPuzzleState fs){
		_v[0]  = fs.get(0, 0);
		_v[1]  = fs.get(0, 1);
		_v[2]  = fs.get(0, fs.getNumCols()-2);
		_v[3]  = fs.get(0, fs.getNumCols()-1);
		_v[4]  = fs.get(1, fs.getNumCols()-1);
		_v[5]  = fs.get(fs.getNumRows()-2, fs.getNumCols()-1);
		_v[6]  = fs.get(fs.getNumRows()-1, fs.getNumCols()-1);
		_v[7]  = fs.get(fs.getNumRows()-1, fs.getNumCols()-2);
		_v[8]  = fs.get(fs.getNumRows()-1, 1);
		_v[9]  = fs.get(fs.getNumRows()-1, 0);
		_v[10] = fs.get(fs.getNumRows()-2, 0);
		_v[11] = fs.get(1, 0);


	}

	//ctor
	public CornerTilesHuristic(SlidingPuzzleState finalState){
		_ver = finalState.getNumCols() > 2;
		_hor = finalState.getNumRows() > 2;
		_luc = finalState.get(0, 0) != 0;
		_ruc = finalState.get(0, finalState.getNumCols()-1)!=0;
		_llc = finalState.get(finalState.getNumRows()-1, 0) !=0;
		_rlc = finalState.get(finalState.getNumRows()-1, finalState.getNumCols()-1) !=0;
		_finalState = finalState;
		
		if (_ver || _hor) loadNumbers(finalState);

	}

	
	/* (non-Javadoc)
	 * @see ai.ex1.heuristics.Heuristic#rank(ai.ex1.SlidingPuzzleState)
	 */
	public int rank(SlidingPuzzleState state) {

		int total = 0;
		int row = state.getNumRows()-1;
		int col = state.getNumCols() -1;
		calculateConflicts(state);
		if (_ver){
			if (_luc && state.get(0, 1)== _v[1] && _v[1]!=0 && state.get(0, 0) != _v[0] &&!_conf[0]){
				total++;
			}
			
			if (_ruc && state.get(0, col-1) == _v[2] && _v[2]!=0 && state.get(0, col)!=_v[3]&&!_conf[1]){
				total++;
			}
			
			
			if (_llc&& state.get(row, 1) == _v[8] && _v[8]!=0 && state.get(row, 0) != _v[9]&&!_conf[5]){
				total++;
			}
			if (_rlc&& state.get(row, col-1) == _v[7] && _v[7]!=0 && state.get(row, col) != _v[6]&&!_conf[4]){
				total++;
			}
		}

		if(_hor){
			if (_luc && state.get(1, 0)== _v[11] && _v[11]!=0 && state.get(0, 0) != _v[0]&&!_conf[7]){
				total++;
			}
			
			if (_ruc && state.get(1, col) == _v[4] && _v[4]!=0 && state.get(0, col)!=_v[3]&&!_conf[3]){
				total++;
			}
			
			
			if (_llc&& state.get(row-1, 0) == _v[10] && _v[10]!=0 && state.get(row, 0) != _v[9]&&!_conf[6]){
				total++;
			}
			
			if (_rlc&& state.get(row-1, col) == _v[5] && _v[5]!=0 && state.get(row, col) != _v[6]&&!_conf[3]){
				total++;
			}
		}

		return total;
	}
	
	public static void main(String[] args){
		SlidingPuzzleState fs = new SlidingPuzzleState("I:\\Devel\\AI\\ex1\\finalState.txt");
		SlidingPuzzleState s = new SlidingPuzzleState("I:\\Devel\\AI\\ex1\\state1.txt");
		CornerTilesHuristic h = new CornerTilesHuristic(fs);
		System.out.println(h.rank(s));
		
		
	}
}
